/*
 * server_tcp.c
 *
 *  Created on: 2015年4月3日
 *      Author: wzy
 */

#include <stdlib.h>
#include <stdio.h>
#include <netdb.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <strings.h>
#include <string.h>
#include <libxml/tree.h>
#include <libxml/parser.h>
#include <libxml/xpath.h>
#include <math.h>

#define MAXSIZE 1024

struct locationInfo
{
	char * locationName;
	char * rssi[30];
	char * bssid[30]; 
	int rssiValue[30];
	int size;
};

struct result
{
	char * locationName;
	float edistance;
};

void syncData(char *);
void stringAnalysis(char *, struct locationInfo *);
xmlXPathObjectPtr get_nodeset(xmlDocPtr doc, const xmlChar * xpath);
char * locate(char *);
void xmlAnalysis(struct locationInfo *, int);
char *  NN(struct result resultValue[], int num);

xmlDocPtr doc = NULL;
xmlNodePtr root_node =NULL, node = NULL, node1 = NULL;

int main()
{
	//xml初始化
	xmlKeepBlanksDefault(0);
	xmlIndentTreeOutput = 1;
	doc = xmlReadFile("wifiinfo.xml","GB2312",XML_PARSE_RECOVER);
	if (NULL == doc)
	{
		doc = xmlNewDoc(BAD_CAST "1.0");	
		root_node = xmlNewNode(NULL, BAD_CAST "wifiinfo");
		xmlDocSetRootElement(doc, root_node);
		xmlSaveFormatFile("wifiinfo.xml", doc, 1);
		xmlFreeDoc(doc);
	}

	int sockfd = 0, newsockfd = 0;
	struct sockaddr_in server_addr;
	struct sockaddr_in client_addr;
	int sin_size, portnumber;
	char buf[4096];
	printf("input portnumber:");
	scanf("%d", &portnumber);
	
	if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
	{
		perror("socket error");
		exit(1);
	}
	else
	{
		printf("socket created successfully\n");
	}

	/*服务器端填充sockaddr结构*/
	bzero(&server_addr, sizeof(struct sockaddr_in));
	server_addr.sin_family = AF_INET;
	server_addr.sin_port = htons(portnumber);
	server_addr.sin_addr.s_addr = htonl(INADDR_ANY);

	if (bind(sockfd, (struct sockaddr *) (&server_addr),
			sizeof(struct sockaddr)) < 0)
	{
		perror("bind failed!");
		exit(1);
	}
	else
	{
		printf("bind successfully\n");
	}

	//服务器开启监听
	if (listen(sockfd, 5) < 0)
	{
		perror("listen error");
		exit(1);
	}
	else
	{
		printf("listening-----\n");
	}
	while (1)
	{
		sin_size = sizeof(struct sockaddr_in);
#ifdef BOARD
		if (newsockfd == 0)
		{
			if ((newsockfd = accept(sockfd, (struct sockaddr *) (&client_addr),
					&sin_size)) < 0)
			{
				perror("accept error!");
				exit(1);
			}
			printf("accept successfully\n\n");
			printf("connect from: %s:%d\n", inet_ntoa(client_addr.sin_addr),
					ntohs(portnumber));
		}
#else
		if ((newsockfd = accept(sockfd, (struct sockaddr *) (&client_addr),
					&sin_size)) < 0)
		{
			perror("accept error!");
			exit(1);
		}
		printf("accept successfully\n");
		printf("connect from: %s:%d\n\n", inet_ntoa(client_addr.sin_addr),
				ntohs(portnumber));
#endif
		int n;
		n = recv(newsockfd, buf, sizeof(buf), 0);
		if (n == -1)
		{
			perror("recv failed!\n");
			exit(1);
		}		
		buf[n] = '\0';
		printf("%s\n\n", buf);	//输出接收到的数据的监控信息
		if ('/' == *buf)		//客户端请求定位
		{
			//printf("%s",locate(buf));
			//send(newsockfd, "send successfully!\n", 20, 0);
			//char sendBuf[20];
			char * sendBuf = locate(buf);
			//sprintf(sendBuf, "%s\n", locate(buf));
			printf("此时的位置为%s\n\n", sendBuf);
			send(newsockfd, sendBuf, strlen(sendBuf), 0);
			send(newsockfd, "\0", 1, 0);
		}
		else					//客户端请求同步信息
		{
			syncData(buf);
		}
#ifndef BOARD
		close(newsockfd);
#endif
	}
	close(sockfd);
	return 0;
}

/**
 *	字符串解析，解析到locationInfo结构体中
 */
void stringAnalysis(char * str, struct locationInfo * info)
{
	char *p[30];
	int num = 0;
	char * buf = str;
	char * wifiinfo[3];
	int i = 0;
	int j = 0;

	while ((p[num]=strtok(buf, " ")) != NULL) 
	{
		num++;
		buf = NULL;
	}

	buf = p[0];

	while((wifiinfo[j]=strtok(buf, "|")) != NULL) 
	{	
		j++;
		buf = NULL;
	}

	info->size = num;
	info->locationName = wifiinfo[0];
	info->rssi[0] = wifiinfo[1];
	info->bssid[0] = wifiinfo[2];

	for (i = 1; i < num; i++)
	{
		char * wifiinfo[2];
		buf = p[i];
		j = 0;
		while((wifiinfo[j]=strtok(buf, "|")) != NULL) 
		{	
			j++;
			buf = NULL;
		}
		info->rssi[i] = wifiinfo[0];
		info->bssid[i] = wifiinfo[1];
	}
}

/**
 *	同步数据
 */ 
void syncData(char * str)
{
	int i, j;
	xmlNodePtr locationName_node;
	xmlNodePtr bssid_node;
	char * locationName = NULL;
	char * rssi = NULL;
	char * bssid = NULL;
	
	struct locationInfo lcInfo;
	for (i = 0; i < 30; i++)
	{
		lcInfo.rssi[i] = (char *)malloc(5 * sizeof(char[20]));
		lcInfo.bssid[i] = (char *)malloc(30 * sizeof(char[20]));
	}
	
	stringAnalysis(str, &lcInfo);
	
	locationName = lcInfo.locationName;
	
	doc = xmlReadFile("wifiinfo.xml","GB2312",XML_PARSE_RECOVER);
	root_node = xmlDocGetRootElement(doc);
	
	locationName_node = NULL;
	locationName_node = xmlNewChild(root_node,NULL,BAD_CAST"locationName",NULL);
	xmlNewProp(locationName_node,BAD_CAST "Name",BAD_CAST locationName);
	xmlAddChild(root_node, locationName_node);
	xmlSaveFormatFile("wifiinfo.xml", doc, 1);

	for (i = 0; i < lcInfo.size; i++)
	{
		rssi = NULL;
		bssid = NULL;
		rssi = lcInfo.rssi[i];
		bssid = lcInfo.bssid[i];

		bssid_node = NULL;
		bssid_node = xmlNewChild(locationName_node, NULL, BAD_CAST "ap", BAD_CAST rssi);
		xmlNewProp(bssid_node, BAD_CAST "bssid",BAD_CAST bssid);
		xmlAddChild(locationName_node, bssid_node);
		xmlSaveFormatFile("wifiinfo.xml", doc, 1); 
	}
}


/**
 * xml解析，获取xml中某一项元素
 */ 
xmlXPathObjectPtr get_nodeset(xmlDocPtr doc, const xmlChar* xpath)
{
	xmlXPathContextPtr context;
	xmlXPathObjectPtr result;
	context = xmlXPathNewContext(doc);
	if (NULL == context)
	{
		printf("context is NULL");
		return NULL;
	}
	result = xmlXPathEvalExpression(xpath, context);

	xmlXPathFreeContext(context);

	if (result == NULL) {
		printf("xmlXPathEvalExpression return NULL\n");
		return NULL;
	}

	if (xmlXPathNodeSetIsEmpty(result->nodesetval)) 
	{
		xmlXPathFreeObject(result);
		printf("nodeset is empty\n");
		return NULL;
	}
	return result;
}

/**
 *	xml解析，数据存放到一个locationInfo 结构体中，
 *	param:	infoTemp		存放数据
 *			no				元素编号
 */ 
void xmlAnalysis(struct locationInfo * infoTemp, int no)
{
	int i;
	doc = xmlReadFile("wifiinfo.xml","GB2312",XML_PARSE_RECOVER);
	xmlChar * value;
	xmlXPathObjectPtr locationNamePtr = get_nodeset(doc, "/wifiinfo/locationName");
	xmlNodeSetPtr locationNameset = locationNamePtr->nodesetval;
	xmlNodePtr cur = locationNameset->nodeTab[no];
	value = xmlGetProp(cur, BAD_CAST "Name");
	infoTemp->locationName = value;
	//xmlFree(value);

	char childName[50];
	sprintf(childName, "/wifiinfo/locationName[%d]/ap", no+1);
	xmlXPathObjectPtr apPtr = get_nodeset(doc, childName);
	if (apPtr)
	{
		xmlNodeSetPtr apSet = apPtr->nodesetval;
		int j;
		for (j = 0; j < apSet->nodeNr; j++)
		{
			infoTemp->size = apSet->nodeNr;

			xmlNodePtr cur = apSet->nodeTab[j];
			value =xmlGetProp(cur, BAD_CAST "bssid");
			infoTemp->bssid[j] = value;
			//xmlFree(value);
			value = xmlNodeGetContent(cur);
			infoTemp->rssi[j] = value;
			infoTemp->rssiValue[j] = atoi(infoTemp->rssi[j]);
			//xmlFree(value);
		}
	}
}

/**
 *	定位
 *	param:	str 待解析字符串
 */ 
char * locate(char * str)
{	
	int i = 0;
	int num = 0;
	struct locationInfo lcInfoTemp;
	struct locationInfo lcInfo;
	struct result resultValue[30];
	for (i = 0; i < 30; i++)
	{
		lcInfoTemp.rssi[i] = (char *)malloc(5 * sizeof(char[20]));
		lcInfoTemp.bssid[i] = (char *)malloc(5 * sizeof(char[20]));
		lcInfo.rssi[i] = (char *)malloc(5 * sizeof(char[20]));
		lcInfo.bssid[i] = (char *)malloc(30 * sizeof(char[20]));
		resultValue[i].edistance = 0.0f;
	}

	stringAnalysis(str, &lcInfo);
	for (i = 0; i < lcInfo.size; i++)
	{
		lcInfo.rssiValue[i] = atoi(lcInfo.rssi[i]);
	}

	//解析xml
	xmlXPathObjectPtr locationNamePtr = get_nodeset(doc, "/wifiinfo/locationName");
	xmlNodeSetPtr locationNameset = locationNamePtr->nodesetval;

	if (locationNamePtr)
	{
		for (i = 0; i < locationNameset->nodeNr; i++ )
		{
			int j, k;
			xmlAnalysis(&lcInfoTemp, i);
			//printf("%s\n", lcInfoTemp.locationName);
			resultValue[i].locationName = lcInfoTemp.locationName;
			for (j = 0; j < lcInfo.size; j++)
			{	
				int hasElement = 0;
				for (k = 0; k < lcInfoTemp.size; k++)
				{
					if (strcmp(lcInfo.bssid[j],lcInfoTemp.bssid[k]) == 0)
					{
						//printf("%s == %s", lcInfo.bssid[j], lcInfoTemp.bssid[k]);
						//计算欧几里德距离
						resultValue[i].edistance += (float)((lcInfo.rssiValue[j] - lcInfoTemp.rssiValue[k])*(lcInfo.rssiValue[j] - lcInfoTemp.rssiValue[k]));
						hasElement = 1;
						break;
					}
				}
				if (!hasElement)
				{
					resultValue[i].edistance += (float)((lcInfo.rssiValue[j] + 100)*(lcInfo.rssiValue[j] + 100));
					hasElement = 1;
				}

			}
			resultValue[i].edistance = sqrt(resultValue[i].edistance);
			printf("NO.%d为%f\n", i+1, resultValue[i].edistance);	//欧式距离运算监控
		}
		return NN(resultValue, locationNameset->nodeNr);
	}

	return NULL;
}

/**
 *	NN算法
 *	param:	resultValue[]	存欧几里德距离的结构体数组
 *			num				数组长度
 */ 
char * NN(struct result resultValue[], int num)
{
	float min =1000;
	int locateNo = 0;
	int i = 0;
	for (i = 0; i < num; i++)
	{
		if (resultValue[i].edistance < min && resultValue[i].edistance != 0)
		{
			min = resultValue[i].edistance;
			resultValue[i].edistance = 0;	//清空数据便于下次处理
			locateNo = i;
		}
	}

	//printf("%s\n",resultValue[locateNo].locationName);
	return resultValue[locateNo].locationName;
}



